/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#ifndef MCPY_BUILTINS_SET_EXTENSION_H
#define MCPY_BUILTINS_SET_EXTENSION_H

#include <mc/traits.h>
#include <mc/variant.h>
#include <mc/variant/copy_context.h>
#include <mc/variant/variant_extension.h>
#include <string>
#include <unordered_set>

namespace mcpy {
namespace detail {

/**
 * @brief set 的内部实现
 *
 * @tparam T 元素类型，默认为 mc::variant（弱类型 set）
 * @tparam Hash 哈希函数类型
 * @tparam KeyEqual 相等比较函数类型
 * @tparam Allocator 分配器类型
 */
template <typename T        = mc::variant,
          typename Hash     = std::hash<T>,
          typename KeyEqual = std::equal_to<T>>
class set_impl : public mc::variant_extension<set_impl<T, Hash, KeyEqual>> {
public:
    using container_type = std::unordered_set<T, Hash, KeyEqual>;
    using value_type     = T;
    using iterator       = typename container_type::iterator;
    using const_iterator = typename container_type::const_iterator;

    set_impl() = default;

    set_impl(std::initializer_list<T> init) : m_data(init) {
    }

    explicit set_impl(const container_type& data) : m_data(data) {
    }
    explicit set_impl(container_type&& data) : m_data(std::move(data)) {
    }

    // 拷贝和移动
    set_impl(const set_impl& other)                = default;
    set_impl(set_impl&& other) noexcept            = default;
    set_impl& operator=(const set_impl& other)     = default;
    set_impl& operator=(set_impl&& other) noexcept = default;

    // ========================================================================
    // variant_extension_base 接口实现，这样就可以放到 mc::variant 中
    // ========================================================================

    std::string_view get_type_name() const override {
        return "set";
    }

    bool equals(const mc::variant_extension_base& other) const override {
        if (auto other_set = dynamic_cast<const set_impl*>(&other)) {
            return m_data == other_set->m_data;
        }
        return false;
    }

    std::size_t hash() const override {
        std::size_t h = 0;
        for (const auto& item : m_data) {
            h ^= Hash{}(item) + 0x9e3779b9 + (h << 6) + (h >> 2);
        }
        return h;
    }

    std::string as_string() const override {
        std::string result = "{";
        bool        first  = true;
        for (const auto& item : m_data) {
            if (!first) {
                result += ", ";
            }
            first = false;
            // 根据元素类型选择转换方式
            if constexpr (std::is_same_v<T, std::string>) {
                result += "\"" + item + "\""; // 字符串加引号
            } else if constexpr (std::is_same_v<T, mc::variant>) {
                result += item.as_string();
            } else if constexpr (std::is_arithmetic_v<T>) {
                result += std::to_string(item);
            } else {
                result += "<item>";
            }
        }
        result += "}";
        return result;
    }

    /**
     * @brief 浅拷贝（拷贝构造）
     */
    mc::shared_ptr<mc::variant_extension_base> copy() const override {
        return mc::make_shared<set_impl>(*this);
    }

    /**
     * @brief 深拷贝
     * @param ctx 深拷贝上下文，用于循环引用检测
     * @return 新的 set_impl 指针（递归深拷贝所有元素）
     */
    mc::shared_ptr<mc::variant_extension_base> deep_copy(mc::detail::copy_context* ctx = nullptr) const override {
        if (!ctx) {
            mc::detail::copy_context local_ctx;
            return deep_copy(&local_ctx);
        }

        // 检测循环引用：如果 this 已经被拷贝过，直接返回已拷贝的版本
        if (ctx->has_copied(this)) {
            return ctx->get_copied<set_impl>(this);
        }

        // 创建新的 set_impl 并记录到上下文
        auto result = mc::make_shared<set_impl>();
        ctx->record_copied(this, result);

        // 递归深拷贝元素，deep_copy > copy > 直接拷贝
        if constexpr (mc::traits::has_deep_copy_v<T>) {
            // 优先使用深拷贝
            for (const auto& item : m_data) {
                result->insert(item.deep_copy(ctx));
            }
        } else if constexpr (mc::traits::has_copy_v<T>) {
            // 其次使用浅拷贝
            for (const auto& item : m_data) {
                result->insert(item.copy());
            }
        } else {
            // 最后直接拷贝
            for (const auto& item : m_data) {
                result->insert(item);
            }
        }
        return result;
    }

    // ========================================================================
    // Set 接口
    // ========================================================================

    // 插入元素
    void insert(const T& item) {
        m_data.insert(item);
    }

    void insert(T&& item) {
        m_data.insert(std::move(item));
    }

    // 删除元素
    void erase(const T& item) {
        m_data.erase(item);
    }

    iterator erase(iterator pos) {
        return m_data.erase(pos);
    }

    // 查找元素
    iterator find(const T& item) {
        return m_data.find(item);
    }

    const_iterator find(const T& item) const {
        return m_data.find(item);
    }

    // 成员检测
    bool contains(const T& item) const {
        return m_data.find(item) != m_data.end();
    }

    // 大小
    std::size_t size() const {
        return m_data.size();
    }

    bool empty() const {
        return m_data.empty();
    }

    // 清空
    void clear() {
        m_data.clear();
    }

    // 获取底层容器
    const container_type& data() const {
        return m_data;
    }

    container_type& data() {
        return m_data;
    }

    // 迭代器
    iterator begin() {
        return m_data.begin();
    }

    iterator end() {
        return m_data.end();
    }

    const_iterator begin() const {
        return m_data.begin();
    }

    const_iterator end() const {
        return m_data.end();
    }

    // 运算符重载
    bool operator==(const set_impl& other) const {
        return m_data == other.m_data;
    }

    bool operator!=(const set_impl& other) const {
        return m_data != other.m_data;
    }

    /**
     * @brief 转换为 variants（用于类型转换）
     *
     * 覆盖基类的 as_array() 虚函数，提供 set -> array 的转换能力
     * 这样可以支持跨类型的 set 转换（如 set<int> -> set<variant>）
     */
    mc::variants as_array() const {
        mc::variants result;
        result.reserve(m_data.size());
        for (const auto& item : m_data) {
            mc::variant v;
            to_variant(item, v);
            result.emplace_back(std::move(v));
        }
        return result;
    }

    void visit(std::function<void(const mc::variant&)>&& visitor) const override {
        for (const auto& item : m_data) {
            visitor(item);
        }
    }

private:
    container_type m_data;
};

} // namespace detail
} // namespace mcpy

#endif // MCPY_BUILTINS_SET_EXTENSION_H
